package zilvic.resources.sprites;

import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;

import javax.imageio.ImageIO;

/**
 * A resource manager for sprites in the game. Its often quite important
 * how and where you get your game resources from. In most cases
 * it makes sense to have a central resource loader that goes away, gets
 * your resources and caches them for future use.
 * <p>
 * [singleton]
 * <p>
 * @author Kevin Glass
 */
public class SpriteStore {
    /** The single instance of this class */
    private static SpriteStore single = new SpriteStore();

    /**
     * Get the single instance of this class
     *
     * @return The single instance of this class
     */
    public static SpriteStore get() {
            return single;
    }

    /** The cached sprite map, from reference to sprite instance */
    private HashMap sprites = new HashMap();

    /**
     * Retrieve a sprite from the store
     *
     * @param ref The reference to the image to use for the sprite
     * @return A sprite instance containing an accelerate image of the request reference
     */
    public Sprite getSprite(String ref) {
            // if we've already got the sprite in the cache
            // then just return the existing version
            if (sprites.get(ref) != null) {
                    return (Sprite) sprites.get(ref);
            }

            // otherwise, go away and grab the sprite from the resource
            // loader
            BufferedImage sourceImage = null;

            try {
                    // The ClassLoader.getResource() ensures we get the sprite
                    // from the appropriate place, this helps with deploying the game
                    // with things like webstart. You could equally do a file look
                    // up here.
                    URL url = this.getClass().getClassLoader().getResource(ref);

                    if (url == null) {
                            fail("Can't find ref: "+ref);
                    }

                    // use ImageIO to read the image in
                    sourceImage = ImageIO.read(url);
            } catch (IOException e) {
                    fail("Failed to load: "+ref);
            }

            // create an accelerated image of the right size to store our sprite in
            GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
            Image image = gc.createCompatibleImage(sourceImage.getWidth(),sourceImage.getHeight(),Transparency.BITMASK);

            // draw our source image into the accelerated image
            image.getGraphics().drawImage(sourceImage,0,0,null);

            // create a sprite, add it the cache then return it
            Sprite sprite = new Sprite(image, ref);
            sprites.put(ref,sprite);

            return sprite;
    }

    /**
     * Retrieve a sequence from the store
     *
     * @param ref The reference to the image to use for the sequence
     * @return A sequence instance containing an accelerate image of the
     * request reference
     */
    public Sequence getSequence(String ref) {
        return getSprite(ref).toSequence();
    }

    /**
     * Retrieve an ActorSprite from the store
     *
     * @param ref The reference to the image to use for the ActorSprite
     * @return An ActorSprite instance containing an accelerate image of the
     * request reference
     */
    public ActorSprite getActorSprite(String ref) {
        return getSprite(ref).toActorSprite();
    }

    /**
     * Utility method to handle resource loading failure
     *
     * @param message The message to display on failure
     */
    private void fail(String message) {
            throw new IllegalArgumentException(message);
    }
}